package middleware

import (
	"net/http"
	"runtime/debug"

	"github.com/gin-gonic/gin"
	"github.com/google/uuid"
	http2 "go-api-template/api/http"
	"go-api-template/internal/e"
	"go-api-template/internal/util"
	"go-api-template/service"
	"golang.org/x/time/rate"
)

var (
	log = service.Log
)

// BaseMid 通用中间件
func BaseMid() gin.HandlerFunc {
	return func(c *gin.Context) {
		requestId := util.GetRequestId()
		c.Writer.Header().Add("RequestId", requestId)
		c.Set("request_id", requestId)
		c.Next()
	}
}

// Recover 异常中间件
func Recover(ctx *gin.Context) {
	defer func() {
		if err := recover(); err != nil {
			var resp http2.Resp
			service.Log.DPanic(string(debug.Stack()))
			resp.SetCode(e.Panic)
			resp.SetData(panicToString(err))
			ctx.JSON(http.StatusOK, resp)
			ctx.Abort()
		}
	}()
	ctx.Next()
}

// CorsMid 跨域中间件
func CorsMid() gin.HandlerFunc {
	return func(c *gin.Context) {
		method := c.Request.Method
		c.Header("Access-Control-Allow-Origin", "*")
		c.Header("Access-Control-Allow-Headers", "*")
		c.Header("Access-Control-Allow-Methods", "POST, GET, OPTIONS, PUT, PATCH, DELETE")
		c.Header("Access-Control-Allow-Credentials", "true")

		// 放行所有OPTIONS方法，因为有的模板是要请求两次的
		if method == "OPTIONS" {
			c.JSON(http.StatusOK, "Options Request!")
			c.Abort()
			return
		}

		// 处理请求
		c.Next()
	}
}

// CurrentLimitMid 限流 - 中间件
func CurrentLimitMid(limiter *rate.Limiter) gin.HandlerFunc {
	return func(c *gin.Context) {
		// 消费token不成功，丢入队列
		if !limiter.Allow() {
			// 队列标识
			c.Set("QueueId", uuid.New().String())
			c.Abort()
			return
		}
		c.Next()
	}
}

// TODO: 请求日志 - 中间件
func _() gin.HandlerFunc {
	return func(c *gin.Context) {
	}
}

func panicToString(r interface{}) string {
	switch v := r.(type) {
	case error:
		return v.Error()
	default:
		return r.(string)
	}
}
